package ar.edu.itba.tp1.gps.api;

import ar.edu.itba.tp1.gps.board.ArithmeticsRestrictions;
import ar.edu.itba.tp1.gps.board.Coordinate;
import ar.edu.itba.tp1.gps.exception.NotAppliableException;

public class GPSRuleImpl implements GPSRule {
	private String name;
	private Integer value;
	private Coordinate coordinate;
	private ArithmeticsRestrictions restrictions;
	
	public GPSRuleImpl(int value, Coordinate coordinate, ArithmeticsRestrictions restrictions) {
		this.name = "Put " + value + " in (" + coordinate.getX() + " ," + coordinate.getY() + ")";
		this.value = value;
		this.coordinate = coordinate;
		this.restrictions = restrictions;
	}

	@Override
	public Integer getCost() {
		return 1;
	}

	@Override
	public String getName() {
		return name;
	}

	@Override
	public GPSState evalRule(GPSState state) throws NotAppliableException {
		Integer i = coordinate.getX();
		Integer j = coordinate.getY();
		Integer[][] stateMatrix = state.getValues();
		
		if (stateMatrix[i][j] != null || !checkRowRestriction(state) || !checkColumnRestriction(state)) {
			throw new NotAppliableException();
		}
		
		if (!restrictions.checkRestriction(state, value, coordinate)) {
			throw new NotAppliableException();
		}
		
		GPSState newState = state.copyState();
		newState.addValue(i, j, value);
		
		return newState;
	}

	private boolean checkRowRestriction(GPSState state) {
		Integer[][] stateMatrix = state.getValues();
		Integer i = coordinate.getX();
		
		for (int j = 0; j < stateMatrix[i].length; j++) {
			if (!(stateMatrix[i][j] == null || stateMatrix[i][j] != value)) {
				return false;
			}
		}
		
		return true;
	}

	private boolean checkColumnRestriction(GPSState state) {
		Integer[][] stateMatrix = state.getValues();
		Integer j = coordinate.getY();
		
		for (int i = 0; i < stateMatrix[j].length; i++) {
			if (!(stateMatrix[i][j] == null || stateMatrix[i][j] != value)) {
				return false;
			}
		}
		
		return true;
	}
	
}
